<template>
  <div style="display: flex; flex-direction: column; width: 100%; height: 90%">
    <ElTable ref="tableRef" v-loading="tableOptions.loading" :row-key="tableOptions.rowKey"
      :height="tableOptions.height" :border="tableOptions.border" :stripe="tableOptions.stripe"
      :size="tableOptions.size" :show-header="tableOptions.showHeader" :data="tableOptions.data"
      :empty-text="tableOptions.noDataText" :highlight-current-row="tableOptions.highlightCurrentRow"
      :row-style="tableOptions.rowStyle" :row-class-name="_rowClassName" :span-method="_spanMethod"
      @selection-change="_onSelectionChange" @sort-change="_onSortChange">
      <Column :cols="cols" :slots="$slots" />
    </ElTable>
    <div class="pagination-wrapper">
      <ElPagination v-if="
        tableOptions.params?.page && tableOptions.params?.size && dataTotal
      " :total="dataTotal" :page-size="tableOptions.params.size" :current-page="tableOptions.params.page"
        :hide-on-single-page="false" layout="slot, prev, pager, next" background @current-change="_pageChange">
        <span>总数 {{ dataTotal }}</span>
      </ElPagination>
    </div>
  </div>
</template>

<script setup>
import { cloneDeep, extend, isArray, isFunction } from 'lodash'
import { ref, watch, computed } from 'vue'
import Column from './column.vue'
import service from '@/utils/api'
import { ElTable } from 'element-plus'

const DEFAULT_TABLE_OPTION = {
  rowKey: null,
  loading: false,
  border: true,
  stripe: false,
  showHeader: true,
  size: 'default',
  noDataText: '暂无数据',
  fixData: false,
  data: [],
  selected: [],
  allSelected: []
}

const DEFAULT_PAGE_OPTION = {
  simple: false,
  pageSizeOpts: [10, 15, 30, 50, 100, 200],
  showSizer: false,
  showTotal: true,
  showElevator: true,
  size: 'default'
}

const { options, columns, pageOption } = defineProps([
  'options',
  'columns',
  'pageOption'
])

const emits = defineEmits([
  'grid-loading',
  'on-data',
  'size-change:grid',
  'page-change:grid',
  'on-reset-all-selected',
  'on-selection-change',
  'on-all-selected',
  'span-method',
  'on-sort-change'
])

const tableRef = ref(null)

const showAllSelected = ref(false)

const tableOptions = ref(extend({}, DEFAULT_TABLE_OPTION, options))

const pageOptions = ref(extend({}, DEFAULT_PAGE_OPTION, pageOption))

const _getDataTotal = () => {
  if (tableOptions.value && tableOptions.value.data) {
    return tableOptions.value.data.length
  }
  return 0
}

const dataTotal = ref(_getDataTotal())

const cols = computed(() => {
  return columns.map(c => getColumn(c))
})

watch(
  () => options,
  newVal => {
    tableOptions.value = extend({}, tableOptions.value, newVal)
  }
)

const getColumn = c => {
  const column = {
    ...c
  }
  return getOtherColumn(column)
}

const getOtherColumn = c => {
  const column = {
    ...c
  }
  const { type } = column

  if (type === 'selection') {
    column.width = 40
    column.align = 'center'
  }

  return {
    align: 'center',
    ...column
  }
}

const _rowClassName = data => {
  if (
    tableOptions.value &&
    tableOptions.value.rowClassName &&
    isFunction(tableOptions.value.rowClassName)
  ) {
    return tableOptions.value.rowClassName(data.row, data.rowIndex)
  }
  return ''
}

const _spanMethod = data => {
  let unionspan = null
  emits('span-method', data, val => {
    unionspan = val
  })
  return unionspan || [1, 1]
}

const _onSelectionChange = newSelection => {
  tableOptions.value.selected = newSelection
  emits('on-selection-change', newSelection)
}

const _onSortChange = data => {
  emits('on-sort-change', data.column, data.prop, data.order)
}

const _setDatas = (datas = []) => {
  tableOptions.value.data = datas || []
  emits('on-data', datas || [])
}

const _setDataTotal = total => {
  dataTotal.value = total
}

const _getLimitData = (page, size, datas = []) => {
  const start = (page - 1) * size
  const end = start + size > datas.length ? datas.length : start + size
  return cloneDeep(datas).splice(start, end)
}

const _setStaticDatas = (datas = []) => {
  const params = tableOptions.value?.params
  if (params) {
    _setDataTotal(datas.length)
    _setDatas(_getLimitData(params.page, params.size, datas))
  } else {
    _setDatas(datas)
  }
}

const _getQueryParams = (options, params) => {
  if (options && options.getParams && isFunction(options.getParams)) {
    return options.getParams(cloneDeep(params))
  }
  return params
}

const _queryDatas = async () => {
  if (!tableOptions.value.url) {
    return false
  }
  if (
    tableOptions.value.validateParams &&
    !tableOptions.value.validateParams(tableOptions.value.params)
  ) {
    return false
  }
  tableOptions.value.loading = true
  emits('grid-loading', true)

  try {
    const params = _getQueryParams(
      tableOptions.value,
      tableOptions.value.params
    )
    const res = await service.get(tableOptions.value.url, {
      params
    })

    let processedData = res
    if (
      tableOptions.value.beforeRender &&
      typeof tableOptions.value.beforeRender === 'function'
    ) {
      processedData = tableOptions.value.beforeRender(res)
    }

    const result = processedData.result || processedData.data || null
    const render = tableOptions.value.render || null

    if (render && typeof render === 'function') {
      _setDataTotal((result && result.total) || 0)
      render(processedData, tableOptions.value, pageOptions.value)
    } else if (result && isArray(result)) {
      _setDataTotal(0)
      _setDatas(result || [])
    } else if (result && result.data && isArray(result.data)) {
      _setDataTotal(result.total || 0)
      _setDatas(result.data || [])
    } else {
      _setDataTotal(0)
      _setDatas([])
    }
  } catch (error) {
    console.error('获取表格数据失败:', error)
    _setDataTotal(0)
    _setDatas([])
  } finally {
    tableOptions.value.loading = false
    emits('grid-loading', false)
  }
}

const inits = () => {
  if (tableOptions.value && !tableOptions.value.data) {
    _setDatas([])
  }
  if (tableOptions.value.fixData) {
    _setStaticDatas(tableOptions.value.data)
  } else {
    _queryDatas()
  }
}

const _resetPage = (options, page = 1) => {
  const params = (options && options.params) || null
  if (params) {
    emits('page-change:grid', page)
    params.page = page || 1
  }
}

const _resetGridData = page => {
  if (page) {
    _resetPage(tableOptions.value, page)
  }
  if (tableOptions.value.fixData) {
    return _setStaticDatas(tableOptions.value.data)
  }
  if (showAllSelected.value) {
    return _setStaticDatas(tableOptions.value.allSelected)
  }
  _queryDatas()
}

const _refreshGrid = page => {
  showAllSelected.value = false
  _resetGridData(page || 1)
}

const _pageChange = page => {
  _resetGridData(page)
}

inits()

defineExpose({
  refreshGrid: (page = 1) => _refreshGrid(page),
  getSelectionRows: () => tableRef.value.getSelectionRows()
  ,
})
</script>

<style scoped>
.pagination-wrapper {
  display: flex;
  justify-content: flex-end;
  margin-top: auto;
}
</style>
